package com.mixsmart.security;

import org.apache.commons.codec.binary.Base64;

import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;

/**
 * 算法定义
 * @author lmq
 *
 */
public abstract class Coder {
	private static final String KEY_SHA = "SHA";
    private static final String KEY_MD5 = "MD5";

    private static final String KEY_SHA_224 = "SHA-224";

    private static final String KEY_SHA_256 = "SHA-256";

    private static final String KEY_SHA_384 = "SHA-384";

    private static final String KEY_SHA_512 = "SHA-512";

    /*
    private static final String KEY_SHA3_224 = "SHA3-224";

    private static final String KEY_SHA3_256 = "SHA3-256";

    private static final String KEY_SHA3_384 = "SHA3-384";

    private static final String KEY_SHA3_512 = "SHA3-512";*/
 
    /**
     * MAC算法可选以下多种算法
     * 
     * <pre>
     * HmacMD5 
     * HmacSHA1 
     * HmacSHA256 
     * HmacSHA384 
     * HmacSHA512
     * </pre>
     */
    public static final String KEY_MAC = "HmacMD5";

    private static final String KEY_HMAC_SHA1 = "HmacSHA1";

    private static final String KEY_HMAC_SHA256 = "HmacSHA256";

    private static final String KEY_HMAC_SHA512 = "HmacSHA512";
 
    /**
     * BASE64解密
     * @param value
     * @return 返回字节数组
     * @throws Exception
     */
    public static byte[] decryptBASE64(String value) throws Exception {
        //return new BASE64Decoder().decodeBuffer(value);
    	//return Base64.decodeBase64(value);
        byte[] keyBytes = Base64.decodeBase64(value);//Base64.getDecoder().decode(value);
        int keyLen = keyBytes.length;
        int size = 16;
        boolean change = false;
        if(keyLen < 16) {
            size = 16;
            change = true;
        } else if(keyLen > 16 && keyLen < 24) {
            size = 24;
            change = true;
        } else if(keyLen > 24 && keyLen < 32) {
            size = 32;
            change = true;
        } else {
            size = keyLen;
        }
        if(change) {
            byte[] tmpKey = new byte[size];
            System.arraycopy(keyBytes, 0, tmpKey, 0, keyLen);
            keyBytes = tmpKey;
        }
        return keyBytes;
    }

    /**
     * BASE64解密
     * @param value
     * @return 返回字节数组
     * @throws Exception
     */
    public static byte[] decryptBase64Utf8(String value) throws Exception {
        //return new BASE64Decoder().decodeBuffer(value);
        //return Base64.decodeBase64(value);
        return org.apache.commons.codec.binary.Base64.decodeBase64(value);
    }

 
    /**
     * BASE64加密
     * 
     * @param bytes
     * @return 返回加密后的值
     * @throws Exception
     */
    public static String encryptBASE64(byte[] bytes) throws Exception {
        //return new BASE64Encoder().encodeBuffer(bytes);
        //return Base64.getEncoder().encodeToString(bytes);
    	return org.apache.commons.codec.binary.Base64.encodeBase64String(bytes);
    }
 
    /**
     * MD5加密
     * @param data
     * @return 返回加密后的值
     * @throws Exception
     */
    public static byte[] encryptMD5(byte[] data) throws Exception {
        MessageDigest md5 = MessageDigest.getInstance(KEY_MD5);
        md5.update(data);
        return md5.digest();
 
    }
 
    /**
     * SHA加密
     * 
     * @param data
     * @return 返回加密后的值
     * @throws Exception
     */
    public static byte[] encryptSHA(byte[] data) throws Exception {
        MessageDigest sha = MessageDigest.getInstance(KEY_SHA);
        sha.update(data);
        return sha.digest();
 
    }

    /**
     * SHA-256加密
     * @param data
     * @return 返回加密后的值
     * @throws Exception
     */
    public static byte[] encryptSHA256(byte[] data) throws Exception {
        MessageDigest sha256 = MessageDigest.getInstance(KEY_SHA_256);
        sha256.update(data);
        return sha256.digest();
    }

    /**
     * SHA-224加密
     * @param data
     * @return 返回加密后的值
     * @throws Exception
     */
    public static byte[] encryptSHA224(byte[] data) throws Exception {
        MessageDigest sha = MessageDigest.getInstance(KEY_SHA_224);
        sha.update(data);
        return sha.digest();
    }

    /**
     * SHA-384加密
     * @param data
     * @return 返回加密后的值
     * @throws Exception
     */
    public static byte[] encryptSHA384(byte[] data) throws Exception {
        MessageDigest sha = MessageDigest.getInstance(KEY_SHA_384);
        sha.update(data);
        return sha.digest();
    }

    /**
     * SHA-512加密
     * @param data
     * @return 返回加密后的值
     * @throws Exception
     */
    public static byte[] encryptSHA512(byte[] data) throws Exception {
        MessageDigest sha = MessageDigest.getInstance(KEY_SHA_512);
        sha.update(data);
        return sha.digest();
    }

    /**
     * SHA3-224加密
     * @param data
     * @return 返回加密后的值
     * @throws Exception
     */
    /*public static byte[] encryptSHA3_224(byte[] data) throws Exception {
        return encryptSHA3(data,224);
    }*/

    /**
     * SHA3加密算法
     * @param data
     * @param bitLen
     * @return 返回加密后的值
     * @throws Exception
     */
    /*private static byte[] encryptSHA3(byte[] data, int bitLen) throws Exception {
        Digest digest = new SHA3Digest(bitLen);
        digest.update(data, 0, data.length);
        byte[] resultData = new byte[digest.getDigestSize()];
        digest.doFinal(resultData, 0);
        return resultData;
    }*/

    /**
     * SHA3-256加密
     * @param data
     * @return 返回加密后的值
     * @throws Exception
     */
    /*public static byte[] encryptSHA3_256(byte[] data) throws Exception {
        return encryptSHA3(data,256);
    }*/

    /**
     * SHA3-384加密
     * @param data
     * @return 返回加密后的值
     * @throws Exception
     */
    /*public static byte[] encryptSHA3_384(byte[] data) throws Exception {
        return encryptSHA3(data,384);
    }*/

    /**
     * SHA3-512加密
     * @param data
     * @return 返回加密后的值
     * @throws Exception
     */
    /*public static byte[] encryptSHA3_512(byte[] data) throws Exception {
        return encryptSHA3(data,512);
    }*/
 
    /**
     * 初始化HMAC密钥
     * 
     * @return 返回初始化Key
     * @throws Exception
     */
    public static String initMacKey() throws Exception {
        KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_MAC);
        SecretKey secretKey = keyGenerator.generateKey();
        return encryptBASE64(secretKey.getEncoded());
    }
 
    /**
     * HmacMD5加密
     * 
     * @param data
     * @param key
     * @return 返回加密后的值
     * @throws Exception
     */
    public static byte[] encryptHMAC(byte[] data, String key) throws Exception {
        return encryptHmac(data, key, KEY_MAC);
    }

    /**
     * HmacSHA1加密
     *
     * @param data
     * @param key
     * @return 返回加密后的值
     * @throws Exception
     */
    public static byte[] encryptHmacSHA1(byte[] data, String key) throws Exception {
        return encryptHmac(data, key, KEY_HMAC_SHA1);
    }

    /**
     * HmacSHA256加密
     *
     * @param data
     * @param key
     * @return 返回加密后的值
     * @throws Exception
     */
    public static byte[] encryptHmacSHA256(byte[] data, String key) throws Exception {
        return encryptHmac(data, key, KEY_HMAC_SHA256);
    }

    /**
     * HmacSHA512加密
     *
     * @param data
     * @param key
     * @return 返回加密后的值
     * @throws Exception
     */
    public static byte[] encryptHmacSHA512(byte[] data, String key) throws Exception {
        return encryptHmac(data, key, KEY_HMAC_SHA512);
    }

    /**
     * Hmac加密
     *
     * @param data
     * @param key
     * @param algorithm 算法名称
     * @return 返回加密后的值
     * @throws Exception
     */
    public static byte[] encryptHmac(byte[] data, String key, String algorithm) throws Exception {
        SecretKey secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), algorithm);
        Mac mac = Mac.getInstance(secretKey.getAlgorithm());
        mac.init(secretKey);
        return mac.doFinal(data);
    }
}
